package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.api.domain.Answer;
import cn.wolfcode.wolf2w.api.domain.AnswerAttention;
import cn.wolfcode.wolf2w.business.mapper.AnswerAttentionMapper;
import cn.wolfcode.wolf2w.business.mapper.AnswerMapper;
import cn.wolfcode.wolf2w.business.query.AnswerQuery;
import cn.wolfcode.wolf2w.business.service.IAnswerService;
import cn.wolfcode.wolf2w.business.util.DateUtil;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.core.exception.ServiceException;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import cn.wolfcode.wolf2w.member.api.RemoteUserInfoService;
import cn.wolfcode.wolf2w.member.api.domain.UserInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 回答Service业务层处理
 *
 * @author 浪兎兎
 * @date 2025-06-07
 */
@Service
@Transactional
public class AnswerServiceImpl extends ServiceImpl<AnswerMapper, Answer> implements IAnswerService {

    @Autowired
    private RemoteUserInfoService userInfoService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private AnswerAttentionMapper answerAttentionMapper;

    @Override
    public IPage<Answer> queryPage(AnswerQuery qo) {
        IPage<Answer> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        LambdaQueryWrapper<Answer> wrapper = new QueryWrapper<Answer>().lambda();
        if (qo.getQuestionId() != null) {
            wrapper.eq(Answer::getQuestionId, qo.getQuestionId());
        }
        return baseMapper.selectPage(page, wrapper);
    }

    @Override
    public IPage<Answer> queryPageByUserId(AnswerQuery qo) {
        IPage<Answer> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        return lambdaQuery()
                .eq(Answer::getUserId, SecurityContextHolder.getUserId())
                .page(page);
    }

    @Override
    public void answer(Answer answer) {
        // 获取当前用户信息
        Long userId = SecurityContextHolder.getUserId();
        UserInfo user = userInfoService.getOne(userId, "inner").getData();

        answer.setAuthorName(user.getNickname());
        answer.setUserId(user.getId());
        answer.setLikeTotal(0);
        answer.setCreateTime(new Date());

        baseMapper.insert(answer);

    }

    @Override
    public void focus(Long id) {
        // 获取 redis 数据
        String key = initFavor(id);
        // 修改 redis 的状态
        Set<Long> cacheSet = redisService.getCacheSet(key);
        Long userId = SecurityContextHolder.getUserId();
        if (cacheSet.contains(userId)) {
            throw new ServiceException("这个回答已经被关注过了");
        }
        redisService.addCacheSetValue(key, userId);
    }

    @Override
    public void unfocus(Long id) {
        // 获取 redis 数据
        String key = initFavor(id);
        // 修改 redis 的状态
        Set<Long> cacheSet = redisService.getCacheSet(key);
        Long userId = SecurityContextHolder.getUserId();
        if (!cacheSet.contains(userId)) {
            throw new ServiceException("这个回答还没有被关注过");
        }
        redisService.deleteCacheSetValue(key, userId);
    }

    @Override
    public void answerPersistence() {
        /// 点赞数
        // 获取 redis 数据
        String statusKey = RedisKeys.ANSWER_STATUS_HASH.join("*");
        List<Answer> answers = redisService.keys(statusKey).stream().map(k -> {
                    Map<String, Object> cacheMap = redisService.getCacheMap(k);
                    Answer answer = new Answer();
                    answer.setId((Long) cacheMap.get("id"));
                    answer.setZanCount((Integer) cacheMap.get("zanCount"));
                    return answer;
                }
        ).collect(Collectors.toList());
        // 存入 MySQL
        this.updateBatchById(answers);
        /// 收藏用户
        answerAttentionMapper.delete(new QueryWrapper<>());
        String favorKey = RedisKeys.ANSWER_FAVOR.join("*");
        redisService.keys(favorKey).forEach(k -> {
            Long id = Long.valueOf(k.substring(k.lastIndexOf(":") + 1));
            redisService.getCacheSet(k).forEach(v -> answerAttentionMapper.insert(new AnswerAttention(id, (Long) v)));
        });
    }

    @Override
    public Long giveLikeAnswer(Long id) {
        // 自身点赞次数 + 1
        String zanKey = RedisKeys.ANSWER_ZAN.join(SecurityContextHolder.getUserId().toString(), id.toString());
        if (!redisService.hasKey(zanKey)) {
            redisService.setCacheObject(zanKey, 0, DateUtil.getDayBetween(DateUtil.getEndTime4day(), new Date()), TimeUnit.SECONDS);
        }
        if (redisService.incrementCacheObjectValue(zanKey, 1L) > 5) {
            throw new ServiceException("每天只能点赞五次");
        }
        // 修改点赞数
        String statusKey = RedisKeys.ANSWER_STATUS_HASH.join(id.toString());
        if (!redisService.hasKey(statusKey)) {
            // 去数据库查询
            Answer answer = baseMapper.selectById(id);
            Map<String, Object> cacheMap = redisService.getCacheMap(statusKey);
            cacheMap.put("zanCount", answer.getZanCount());
            cacheMap.put("id", answer.getId());
            redisService.setCacheMap(statusKey, cacheMap);
        }
        return redisService.incrementCacheMapValue(statusKey, "zanCount", 1L);
    }

    private String initFavor(Long id) {
        // 获取 redis 数据
        String key = RedisKeys.ANSWER_FAVOR.join(id.toString());
        // 如果 redis 没有该问题，去 MySQL 查询数据，同步到 redis
        if (!redisService.hasKey(key)) {
            LambdaQueryWrapper<AnswerAttention> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(AnswerAttention::getUserId).eq(AnswerAttention::getId, id);
            Set<Long> userIds = answerAttentionMapper.selectList(wrapper).stream().map(AnswerAttention::getUserId).collect(Collectors.toSet());
            userIds.add(-1L);
            redisService.setCacheSet(key, userIds);
        }
        return key;
    }
}
